#!/bin/bash
#
# This hook is invoked by 'git-receive-pack' on the remote repository, which
# happens when a 'git-push' is done on a local repository. Just before updating
# the ref on the remote repository, the update hook is invoked. Its exit status
# determines the success or failure of the ref update.
#
# The hook executes once for each ref to be updated and takes three parameters:
# - the name of the ref being updated,
# - the old object name stored in the ref,
# - and the new objectname to be stored in the ref.
#
# A zero exit from the update hook allows the ref to be updated. Exiting with a
# non-zero status prevents 'git-receive-pack' from updating that ref.

if [[ $1 != refs/heads/* ]]; then
	exit 0
fi

readonly tmp=$(mktemp /tmp/git.puppet.update.XXXXXX)
readonly log=$(mktemp /tmp/git.puppet.update.log.XXXXXX)
readonly tree=$(mktemp /tmp/git.puppet.diff-tree.XXXXXX)
trap "rm -f ${log} ${tmp} ${tree}" EXIT

git diff-tree -r "$2" "$3" >${tree}

exit_status=0

while read old_mode new_mode old_sha1 new_sha1 status name; do
	# skip symlinks
	[ "${new_mode}" = '120000' ] && continue
	# skip lines showing parent commit
	test -z "${new_sha1}" && continue
	# skip deletions
	[ "${new_sha1}" = '0000000000000000000000000000000000000000' ] && continue
	# Only test .pp files
	if [[ $name =~ [.]pp$ ]]; then
		git cat-file blob ${new_sha1} >$tmp
		wsfail=$({
			# grep -nPT would be nice. grep -P seems broken on gudeploy01.
			# Patterns checked for are (in this order):
			# - leading SPACE
			# - SPACE followed by TAB
			# - TAB followed by SPACE
			# - non-leading TAB (but allow around '#' comment leader)
			# - trailing whitespace
			pcregrep -n -e '^ ' -e ' \t' -e '\t ' -e '[^\t#]\t+(?!#)' -e '\s+$' ${tmp}
		})
		if [[ $(wc -l <${tmp}) > $(cat -s ${tmp}|wc -l) ]]; then
			wsfail+="Excess blank line(s). 'cat -s' is your friend."
		fi
		if [[ -n "${wsfail}" ]]; then
			echo "** ${name}" >&2
			echo '** Whitespace fail (see Manifest Standards):' >&2
			echo "${wsfail}" >&2
			exit_status=1
			continue
		fi
		# --ignoreimport not working any more, skip manifests that import.
		egrep -q '^import ' ${tmp} || {
			set -o pipefail
			puppet parser validate --color=false --confdir=/tmp --vardir=/tmp ${tmp} >${log} 2>&1
			if [[ $? != 0 ]]; then
				echo "** ${name}" >&2
				echo '** Syntax check fail:' >&2
				sed "s|${tmp}|${name}|" <${log} \
				| fgrep -vx "err: Try 'puppet help parser validate' for usage" >&2
				exit_status=1
			fi
		}
	fi
done <${tree}

if [[ ${exit_status} != 0 ]]; then
	echo "** Have you run 'make git_hooks' in your local repository?" >&2
fi
exit ${exit_status}
